#ifndef _RINGQUEUE_HPP_
#define _RINGQUEUE_HPP_


#include <iostream>
#include <vector>
#include <pthread.h>
#include"sem.hpp"

const int g_default_num = 5;

// 多生产多消费的意义在哪里？？不要狭隘的认为，把任务或者数据放在交易场所，就是生产和消费啦
// 将数据或者任务生产前和拿到之后处理，才是最耗费时间的。
// 生产的本质：私有的任务-> 公共空间中
// 消费的本质：公共空间中的任务-> 私有的

// 信号量本质是一把计数器-> 计数器的意义是什么？？可以不用进入临界区，就可以得知资源情况，甚至可以减少临界区内部的判断！
// 申请锁 -> 判断与访问 -> 释放锁 --> 本质是我们并不清楚临界资源的情况！！
// 信号量要提前预设资源的情况，而且在pv变化过程中，我们可以在外部就能知晓临界资源的情况！
// 


//多线程
template <class T>
class ringQueue
{
public:
    ringQueue(int num = g_default_num)
        : num_(num)
        , rQueue_(num)
        , c_sub(0)
        , p_sub(0)
        , spaceSem(num_)
        , dataSem(0)
    {
        pthread_mutex_init(&c, nullptr);
        pthread_mutex_init(&p, nullptr);
    }

    ~ringQueue()
    {
        pthread_mutex_destroy(&c);
        pthread_mutex_destroy(&p);
    }
     // 消费者: 数据资源， 消费者们的临界资源是什么？下标
    void pop(T* out)
    {
        dataSem.p();
        pthread_mutex_lock(&c);
    // 一定是竞争成功的消费者线程 -- 就一个！
        *out=rQueue_[c_sub++];
        c_sub%=rQueue_.size();
        pthread_mutex_unlock(&c);
        spaceSem.v();
    }

      // 生产者: 空间资源, 生产者们的临界资源是什么？下标
    void push(const T& in)
    {
         // 先申请信号量(0)
        spaceSem.p();
        pthread_mutex_lock(&p);
      // 一定是竞争成功的生产者线程 -- 就一个！
        rQueue_[p_sub++]=in;
        p_sub%=rQueue_.size();
        pthread_mutex_unlock(&p);
        dataSem.v();
    }

private:
    std::vector<T> rQueue_;
    size_t num_;
    int c_sub;// 消费下标
    int p_sub;// 生产下标
    Sem spaceSem;
    Sem dataSem;
    pthread_mutex_t c;
    pthread_mutex_t p;
};

#endif